﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Web.Cms.Cache;
using Proggy.Web.Cms.Repositories;
using System.Diagnostics.CodeAnalysis;
using Proggy.Web.Cms.Repositories.Published;
using Proggy.Web.Cms.ContentModel;
using System.Configuration;
using System.Web;
using Ninject;

namespace Proggy.Web.Cms.Context
{
    /// <summary>
    /// The context of the current request (frontEnd)
    /// </summary>
    public class FrontEndRequestContext : IDisposable
    {
        #region static

        /// <summary>
        /// Context key
        /// </summary>
        public const string CONTEXT_KEY = "CurrentFrontEndContext";

        /// <summary>
        /// Root url getter
        /// </summary>
        private static readonly string _rootUrl =
            string.IsNullOrEmpty(ConfigurationManager.AppSettings["RootUrl"]) ?
            "/" :
            ConfigurationManager.AppSettings["RootUrl"];


        /// <summary>
        /// Current context for the request
        /// </summary>
        public static FrontEndRequestContext Current
        {
            get
            {
                // check
                if (!CurrentIsSet())
                {
                    if (HttpContext.Current != null && HttpContext.Current.Items != null)
                    {
                        // create context
                        var ctx = new FrontEndRequestContext();

                        // try
                        if (tryGetFrontEndContextInstance(ref ctx))
                        {
                            // add to request items
                            HttpContext.Current.Items.Add(CONTEXT_KEY, ctx);

                            // finally, set _current;
                            _current = (FrontEndRequestContext)HttpContext.Current.Items[CONTEXT_KEY];
                        }
                    }
                }

                return _current;
            }
            set
            {
                _current = value;
            }
        }

        /// <summary>
        /// Current is set for current request
        /// </summary>
        /// <returns></returns>
        public static bool CurrentIsSet()
        {
            return
                HttpContext.Current != null &&
                HttpContext.Current.Items != null &&
                HttpContext.Current.Items[CONTEXT_KEY] != null;
        }

        /// <summary>
        /// Try to set front end context
        /// </summary>
        /// <param name="ctx"></param>
        /// <returns></returns>
        private static bool tryGetFrontEndContextInstance(ref FrontEndRequestContext ctx)
        {
            //
            if (HttpContext.Current != null &&
                HttpContext.Current.Request != null &&
                HttpContext.Current.Request.RequestContext != null &&
                HttpContext.Current.Request.RequestContext.RouteData != null &&
                HttpContext.Current.Request.RequestContext.RouteData.Values != null)
            {

                // area
                var area = HttpContext.Current.Request.RequestContext.RouteData.Values["area"];

                // check if in default area
                if (area == null || string.IsNullOrEmpty((string)area))
                {
                    // get action and id
                    var nodeId = Convert.ToInt32(HttpContext.Current.Request.RequestContext.RouteData.Values["nodeId"]);

                    // get instance of repo
                    var repo = CachedContentManager.GetRepositoryInstance(false);

                    if (repo != null)
                    {

                        // set ctx repo
                        ctx.CurrentCachedContentRepository = repo;

                        // get current model
                        var currentModel = ctx.CurrentCachedContentRepository.GetAbstractContentSingleFromId(nodeId);

                        // set ctx
                        ctx.CurrentContentModel = currentModel;
                        ctx.RootUrl = GetRootUrl();

                        return true;
                    }
                    
                }
            }

            return false;
        }

        /// <summary>
        /// Backing field
        /// </summary>
        private static FrontEndRequestContext _current;

        /// <summary>
        /// Returns the root url for the app - available anywhere
        /// </summary>
        /// <returns></returns>
        public static string GetRootUrl()
        {
            return _rootUrl;
        }

        /// <summary>
        /// Refresh current context
        /// </summary>
        public static void RefreshCurrent()
        {
            if (HttpContext.Current != null && HttpContext.Current.Items != null)
            {
                HttpContext.Current.Items.Remove(CONTEXT_KEY);
            }
        }

        /// <summary>
        /// Force current request context (used in "preview")
        /// </summary>
        /// <param name="proggyFrontEndRequestContext"></param>
        public static void ForceCurrent(FrontEndRequestContext proggyFrontEndRequestContext)
        {
            if (HttpContext.Current != null && HttpContext.Current.Items != null)
            {
                // check
                if (HttpContext.Current.Items[CONTEXT_KEY] != null)
                {
                    HttpContext.Current.Items[CONTEXT_KEY] = proggyFrontEndRequestContext;
                }
                else
                {
                    // add to request items
                    HttpContext.Current.Items.Add(CONTEXT_KEY, proggyFrontEndRequestContext);
                }

                // finally, set _current;
                _current = (FrontEndRequestContext)HttpContext.Current.Items[CONTEXT_KEY];
            }
        }


        #endregion

        #region object

        /// <summary>
        /// Browser context
        /// </summary>
        public BrowserContext BrowserContext
        {
            get
            {
                if (this._browserContext == null)
                {
                    this._browserContext = Context.BrowserContext.Current;
                }

                return this._browserContext;
            }
            set
            {
                _browserContext = value;
            }
        }
        private BrowserContext _browserContext;

        /// <summary>
        /// Cached, published content repo instance
        /// </summary>
        public IPublishedContentRepository CurrentCachedContentRepository { get; set; }

        /// <summary>
        /// The root url for the site (available front end only)
        /// </summary>
        public string RootUrl { get; set; }

        /// <summary>
        /// Current model for this requets
        /// </summary>
        public IContentModel CurrentContentModel { get; set; }

        /// <summary>
        /// Is disposed?
        /// </summary>
        private bool _disposed;

        /// <summary>
        /// Dispose
        /// </summary>
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public void Dispose()
        {
            HttpContext.Current.Items.Remove(CONTEXT_KEY);
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// True if object is disposed
        /// </summary>
        public bool IsDisposed { get { return this._disposed; } }

        /// <summary>
        /// Dispose
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;
            }
        }

        #endregion
    }
}
